package com.bringspring.files.controller;

import com.alibaba.fastjson.JSONObject;
import com.bringspring.common.base.ActionResult;
import com.bringspring.common.base.NoDataSourceBind;
import com.bringspring.common.base.UserInfo;
import com.bringspring.common.base.vo.DownloadVO;
import com.bringspring.common.base.vo.ListVO;
import com.bringspring.common.config.ConfigValueUtil;
import com.bringspring.common.constant.MsgCode;
import com.bringspring.common.exception.DataException;
import com.bringspring.common.model.LanguageVO;
import com.bringspring.common.model.UploaderVO;
import com.bringspring.common.util.*;
import com.bringspring.common.util.enums.FileTypeEnum;
import com.bringspring.common.util.file.StorageType;
import com.bringspring.common.util.file.UploadUtil;
import com.bringspring.common.util.minio.MinioUploadUtil;
import com.bringspring.files.model.*;
import com.bringspring.files.utils.YozoUtils;
import com.bringspring.system.base.entity.DictionaryDataEntity;
import com.bringspring.system.base.service.DictionaryDataService;
import com.bringspring.system.base.util.OptimizeUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.Cleanup;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.WritableByteChannel;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 通用控制器
 *
 * @author 开发平台组
 * @version V1.2.191207
 * @copyright 股份有限公司
 * @date 2017年9月26日 上午9:18
 */
@Api(tags = "公共", value = "file")
@RestController
@RequestMapping("/api/file")
public class UtilsController {

    @Autowired
    private ConfigValueUtil configValueUtil;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private UserProvider userProvider;
    @Autowired
    private DictionaryDataService dictionaryDataService;
    @Autowired
    private YozoUtils yozoUtils;
    @Autowired
    private MinioUploadUtil minioUploadUtil;

    /**
     * 语言列表
     *
     * @return
     */
    @ApiOperation("语言列表")
    @GetMapping("/Language")
    public ActionResult<ListVO<LanguageVO>> getList() {
        String dictionaryTypeId = "dc6b2542d94b407cac61ec1d59592901";
        List<DictionaryDataEntity> list = dictionaryDataService.getList(dictionaryTypeId);
        List<LanguageVO> language = JsonUtil.getJsonToList(list, LanguageVO.class);
        ListVO vo = new ListVO();
        vo.setList(language);
        return ActionResult.success(vo);
    }

    /**
     * 图形验证码
     *
     * @return
     */
    @NoDataSourceBind()
    @ApiOperation("图形验证码")
    @GetMapping("/ImageCode/{timestamp}")
    public void imageCode(@PathVariable("timestamp") String timestamp) {
        DownUtil.downCode(null);
        redisUtil.insert(timestamp, ServletUtils.getSession().getAttribute(CodeUtil.RANDOMCODEKEY), 120);
    }

    /**
     * 上传文件/图片
     *
     * @return
     */
    @NoDataSourceBind()
    @ApiOperation("上传文件/图片")
    @PostMapping(value = "/Uploader/{type}", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public ActionResult uploader(@RequestPart("file") MultipartFile file,
                                 @PathVariable("type") String type) throws IOException {
        String fileType = UpUtil.getFileType(file);
        //验证类型
        if (!OptimizeUtil.fileType(configValueUtil.getAllowUploadFileType(), fileType)) {
            return ActionResult.fail(MsgCode.FA017.get());
        }
        UploaderVO vo = uploaderVO(file, type);
        return ActionResult.success(vo);
    }

    /**
     * 上传文件/图片
     *
     * @return
     */
    @NoDataSourceBind()
    @ApiOperation("上传文件/图片")
    @PostMapping(value = "/Uploader/{modular}/{type}", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public ActionResult uploader(@RequestPart("file") MultipartFile file, @PathVariable("modular") String modular,
                                 @PathVariable("type") String type) throws IOException {
        String fileType = UpUtil.getFileType(file);
        //验证类型
        if (!OptimizeUtil.fileType(configValueUtil.getAllowUploadFileType(), fileType)) {
            return ActionResult.fail(MsgCode.FA017.get());
        }
        UploaderVO vo = uploaderVO(file, type, modular);
        return ActionResult.success(vo);
    }

    /**
     * 获取下载文件链接
     *
     * @return
     */
    @NoDataSourceBind()
    @ApiOperation("获取下载文件链接")
    @GetMapping("/Download/{type}/{fileName}")
    public ActionResult<DownloadVO> downloadUrl(@PathVariable("type") String type,
                                                @PathVariable("fileName") String fileName) {
        type = XSSEscape.escape(type);
        fileName = XSSEscape.escape(fileName);
        UserInfo userInfo = userProvider.get();
        if (!configValueUtil.getFileType().equals(StorageType.STORAGE)) { // 非本地存储
            DownloadVO vo =
                    DownloadVO.builder().name(fileName).url(UploaderUtil.uploaderFile(userInfo.getId() + "#" + fileName + "#" + type)).build();
            return ActionResult.success(vo);
        }
        String filePath = FilePathUtil.getFilePath(type) + fileName;
        if (FileUtil.fileIsFile(filePath)) {
            DownloadVO vo =
                    DownloadVO.builder().name(fileName).url(UploaderUtil.uploaderFile(userInfo.getId() + "#" + fileName + "#" + type)).build();
            return ActionResult.success(vo);
        }
        return ActionResult.fail(MsgCode.FA018.get());
    }

    /**
     * 获取下载文件链接
     *
     * @return
     */
    @NoDataSourceBind()
    @ApiOperation("获取下载文件链接")
    @GetMapping("/Download/{type}/{year}/{month}/{day}/{modular}/{fileName}")
    public ActionResult<DownloadVO> downloadUrl(@PathVariable("type") String type,
                                                @PathVariable("year") String year,
                                                @PathVariable("month") String month,
                                                @PathVariable("day") String day,
                                                @PathVariable("modular") String modular,
                                                @PathVariable("fileName") String fileName) {
        /**
         * 2.2 后半段目录 /年/月/日/模块/
         */
        String secondFilePath = year + "/" + month + "/" + day + "/" + modular + "/";
        type = XSSEscape.escape(type);
        fileName = XSSEscape.escape(fileName);
        UserInfo userInfo = userProvider.get();
        if (!configValueUtil.getFileType().equals(StorageType.STORAGE)) { // 非本地存储
            DownloadVO vo =
                    DownloadVO.builder().name(fileName).url(UploaderUtil.uploaderFile(userInfo.getId() + "#" + fileName + "#" + type + "#" + secondFilePath)).build();
            return ActionResult.success(vo);
        }
        String filePath = FilePathUtil.getFilePath(type) + fileName;
        if (FileUtil.fileIsFile(filePath)) {
            DownloadVO vo =
                    DownloadVO.builder().name(fileName).url(UploaderUtil.uploaderFile(userInfo.getId() + "#" + fileName + "#" + type + "#" + secondFilePath)).build();
            return ActionResult.success(vo);
        }
        return ActionResult.fail(MsgCode.FA018.get());
    }

    /**
     * 下载文件链接
     *
     * @return
     */
    @NoDataSourceBind()
    @ApiOperation("下载文件链接")
    @GetMapping("/Download")
    public void downloadFile() throws DataException {
        UserInfo userInfo = userProvider.get();
        HttpServletRequest request = ServletUtils.getRequest();
        String reqJson = request.getParameter("encryption");
        String name = request.getParameter("name");
        String fileNameAll = DesUtil.aesDecode(reqJson);
        if (!StringUtils.isEmpty(fileNameAll)) {
            String[] data = fileNameAll.split("#");
            String token = data.length > 0 ? data[0] : "";
            //验证token
            if (redisUtil.exists(token)) {
                String fileName = data.length > 1 ? data[1] : "";
                String type = data.length > 2 ? data[2] : "";
                String secondFilePath = data.length > 3 ? data[3] : "";

                /**
                 *  2.1 通过fileType获取文件保存目录/minio的bucketName
                 *  win或Linux本地存储路径
                 */
                String bucketName = type.toLowerCase(); // 初始化 minio的bucketName
                String filePath = FilePathUtil.getFilePath(bucketName); // 获取win或Linux本地存储路径
                if (StringUtils.isNotEmpty(filePath)) {
                    String[] arr = filePath.split("/|\\\\");
                    if (arr.length > 0) {
                        bucketName = arr[arr.length - 1];
                    }
                }
                //下载文件
                if (StringUtils.isNotEmpty(secondFilePath)) {
                    UploadUtil.downFile(configValueUtil.getFileType(), fileName, bucketName, filePath, secondFilePath, name);
                } else {
                    UploadUtil.downFile(configValueUtil.getFileType(), fileName, type, filePath, name);
                }
            } else {
                throw new DataException("token验证失败");
            }
        }
    }

    /**
     * 下载文件链接
     *
     * @return
     */
    @NoDataSourceBind()
    @ApiOperation("下载模板文件链接")
    @GetMapping("/DownloadModel")
    public void downloadModel() throws DataException {
        HttpServletRequest request = ServletUtils.getRequest();
        String reqJson = request.getParameter("encryption");
        String fileNameAll = DesUtil.aesDecode(reqJson);
        if (!StringUtils.isEmpty(fileNameAll)) {
            String token = fileNameAll.split("#")[0];
            if (redisUtil.exists(token)) {
                String fileName = fileNameAll.split("#")[1];
                String filePath = configValueUtil.getTemplateFilePath();
                //下载文件
                UploadUtil.downFile(configValueUtil.getFileType(), fileName, FileTypeEnum.TEMPLATEFILE, filePath, null);
            }
        }
    }

//    @CrossOrigin
//    @ApiOperation("ios视频预览")
//    @GetMapping("/ios/video/range")
//    public void iosVideoRange(@RequestParam("url") String url, HttpServletRequest request, HttpServletResponse
//    response) throws IOException {
//        File file = new File(url);
//        MimeType mimeType = FileStorageUtil.getMimeType(Files.newInputStream(file.toPath()), file.getName());
//        RandomAccessFile randomFile = new RandomAccessFile(file, "r");
//        long contentLength = randomFile.length();
//        String range = request.getHeader("Range");
//        int start = 0, end = 0;
//        if (range != null && range.startsWith("bytes=")) {
//            String[] values = range.split("=")[1].split("-");
//            start = Integer.parseInt(values[0]);
//            if (values.length > 1) {
//                end = Integer.parseInt(values[1]);
//            }
//        }
//        int requestSize = 0;
//        if (end != 0 && end > start) {
//            requestSize = end - start + 1;
//        } else {
//            requestSize = Integer.MAX_VALUE;
//        }
//        String mimeTypeName = "video/mp4";
//        if (mimeType != null) {
//            mimeTypeName = mimeType.getName();
//        }
//        response.setContentType(mimeTypeName);
//        response.setHeader("Accept-Ranges", "bytes");
//        response.setHeader("ETag", file.getName());
//        response.setHeader("Last-Modified", new Date().toString());
//        //第一次请求只返回content length来让客户端请求多次实际数据
//        if (range == null) {
//            response.setHeader("Content-length", contentLength + "");
//        } else {
//            //以后的多次以断点续传的方式来返回视频数据
//            response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);//206
//            long requestStart = 0, requestEnd = 0;
//            String[] ranges = range.split("=");
//            if (ranges.length > 1) {
//                String[] rangeDatas = ranges[1].split("-");
//                requestStart = Integer.parseInt(rangeDatas[0]);
//                if (rangeDatas.length > 1) {
//                    requestEnd = Integer.parseInt(rangeDatas[1]);
//                }
//            }
//            long length = 0;
//            if (requestEnd > 0) {
//                length = requestEnd - requestStart + 1;
//                response.setHeader("Content-length", "" + length);
//                response.setHeader("Content-Range", "bytes " + requestStart + "-" + requestEnd + "/" + contentLength);
//            } else {
//                length = contentLength - requestStart;
//                response.setHeader("Content-length", "" + length);
//                response.setHeader("Content-Range", "bytes " + requestStart + "-" + (contentLength - 1) + "/" +
//                contentLength);
//            }
//        }
//        ServletOutputStream out = response.getOutputStream();
//        int needSize = requestSize;
//        randomFile.seek(start);
//        while (needSize > 0) {
//            byte[] buffer = new byte[4096];
//            int len = randomFile.read(buffer);
//            if (needSize < buffer.length) {
//                out.write(buffer, 0, needSize);
//            } else {
//                out.write(buffer, 0, len);
//                if (len < buffer.length) {
//                    break;
//                }
//            }
//            needSize -= buffer.length;
//        }
//        randomFile.close();
//        out.close();
//        file.delete();
//    }

    /**
     * 获取图片
     *
     * @param fileName
     * @param type
     * @return
     */
    @NoDataSourceBind()
    @ApiOperation("获取图片")
    @GetMapping("/Image/{type}/{fileName}")
    public void downLoadImg(@PathVariable("type") String type, @PathVariable("fileName") String fileName) {
        String filePath = FilePathUtil.getFilePath(type.toLowerCase());
        if (FileTypeEnum.IM.equalsIgnoreCase(type)) {
            type = "imfile";
        } else if (FileTypeEnum.ANNEX.equalsIgnoreCase(type)) {
            type = FileTypeEnum.ANNEXPIC;
        }
        //下载文件
        UploadUtil.writeImage(configValueUtil.getFileType(), fileName, type.toLowerCase(), filePath);
    }

    /**
     * 获取图片
     *
     * @param fileName
     * @param type
     * @return
     */
    @NoDataSourceBind()
    @ApiOperation("获取图片")
    @GetMapping("/Image/{type}/{year}/{month}/{day}/{modular}/{fileName}")
    public void downLoadImg(@PathVariable("type") String type, @PathVariable("year") String year, @PathVariable(
            "month") String month, @PathVariable("day") String day, @PathVariable("modular") String modular,
                            @PathVariable("fileName") String fileName) {
        /**
         *  2.1 通过fileType获取文件保存目录/minio的bucketName
         *  win或Linux本地存储路径
         */
        String bucketName = type.toLowerCase(); // 初始化 minio的bucketName
        String filePath = FilePathUtil.getFilePath(bucketName); // 获取win或Linux本地存储路径
        if (StringUtils.isNotEmpty(filePath)) {
            String[] arr = filePath.split("/|\\\\");
            if (arr.length > 0) {
                bucketName = arr[arr.length - 1];
            }
        }
        /**
         * 2.2 后半段目录 /年/月/日/模块/
         */
        String secondFilePath = year + "/" + month + "/" + day + "/" + modular + "/";
        //下载文件
        UploadUtil.writeImage(configValueUtil.getFileType(), fileName, bucketName, filePath, secondFilePath);
    }

    /**
     * 获取IM聊天图片
     * 注意 后缀名前端故意把 .替换@
     *
     * @param fileName
     * @return
     */
    @NoDataSourceBind()
    @ApiOperation("获取IM聊天图片")
    @GetMapping("/IMImage/{fileName}")
    public void imImage(@PathVariable("fileName") String fileName) {
        //下载文件
        UploadUtil.downFile(configValueUtil.getFileType(), fileName, "imfile",
                FilePathUtil.getFilePath(FileTypeEnum.IM) + fileName, null);
    }

    /**
     * 查看图片
     *
     * @param type     哪个文件夹
     * @param fileName 文件名称
     * @return
     */
    @NoDataSourceBind()
    @ApiOperation("查看图片")
    @GetMapping("/{type}/{fileName}")
    public void img(@PathVariable("type") String type, @PathVariable("fileName") String fileName) {
        String filePath = configValueUtil.getBiVisualPath() + type + File.separator;
        if (StorageType.MINIO.equals(configValueUtil.getFileType())) {
            fileName = "/" + type + "/" + fileName;
            filePath = configValueUtil.getBiVisualPath().substring(0, configValueUtil.getBiVisualPath().length() - 1);
        }
        //下载文件
        UploadUtil.downFile(configValueUtil.getFileType(), fileName, FileTypeEnum.BIVISUALPATH, filePath, null);
    }

    /**
     * 获取IM聊天语音
     * 注意 后缀名前端故意把 .替换@
     *
     * @param fileName
     * @return
     */
    @NoDataSourceBind()
    @ApiOperation("获取IM聊天语音")
    @GetMapping("/IMVoice/{fileName}")
    public void imVoice(@PathVariable("fileName") String fileName) {
        String paths = FilePathUtil.getFilePath(FileTypeEnum.IM) + fileName.replaceAll("@", ".");
        UploadUtil.downFile(configValueUtil.getFileType(), fileName, "imfile", paths, null);
    }

    /**
     * app启动获取信息
     *
     * @param appName
     * @return
     */
    @NoDataSourceBind()
    @ApiOperation("app启动获取信息")
    @GetMapping("/AppStartInfo/{appName}")
    public ActionResult getAppStartInfo(@PathVariable("appName") String appName) {
        appName = XSSEscape.escape(appName);
        JSONObject object = new JSONObject();
        object.put("AppVersion", configValueUtil.getAppVersion());
        object.put("AppUpdateContent", configValueUtil.getAppUpdateContent());
        return ActionResult.success(object);
    }

    //----------大屏图片下载---------
    @NoDataSourceBind()
    @ApiOperation("获取图片")
    @GetMapping("/VisusalImg/{type}/{fileName}")
    public void downVisusalImg(@PathVariable("type") String type, @PathVariable("fileName") String fileName) {
        type = XSSEscape.escape(type);
        fileName = XSSEscape.escape(fileName);
        String filePath = FilePathUtil.getFilePath(FileTypeEnum.BIVISUALPATH) + type + File.separator;
        if (StorageType.MINIO.equals(configValueUtil.getFileType())) {
            fileName = "/" + type + "/" + fileName;
        }
        UploadUtil.downFile(configValueUtil.getFileType(), fileName, FileTypeEnum.BIVISUALPATH, filePath, null);
    }

    //----------------------

    @NoDataSourceBind()
    @ApiOperation("预览文件")
    @GetMapping("/Uploader/Preview")
    public ActionResult Preview(PreviewParams previewParams) {
        //读取允许文件预览类型
        String allowPreviewType = configValueUtil.getAllowPreviewFileType();
        String[] fileType = allowPreviewType.split(",");

        String fileName = XSSEscape.escape(previewParams.getFileName());

        //文件预览类型检验
        String docType = fileName.substring(fileName.lastIndexOf(".") + 1);
        String s = Arrays.asList(fileType).stream().filter(type -> type.equals(docType)).findFirst().orElse(null);

        if (StringUtils.isEmpty(s)) {
            return ActionResult.fail("预览失败,请检查文件类型是否规范");
        }

        //解析文件url 获取类型
        String type = FileTypeEnum.ANNEX;

        String secondFilePath = previewParams.getSecondFilePath();
        String fileNameAll = previewParams.getFileDownloadUrl();
        if (!StringUtils.isEmpty(fileNameAll)) {
            String[] data = fileNameAll.split("/");
            type = data.length > 4 ? data[4] : "";
        }

        String url;
        //文件预览策略
        if ("yozo".equals(configValueUtil.getPreviewType())) {
            if (StringUtils.isEmpty(previewParams.getFileVersionId())) {
                return ActionResult.fail("预览失败,请重新上传文件");
            }

            String fileVersionId = XSSEscape.escape(previewParams.getFileVersionId());

            //获取签名
            Map<String, String[]> parameter = new HashMap<String, String[]>();
            parameter.put("appId", new String[]{YozoParams.APP_ID});
            parameter.put("fileVersionId", new String[]{fileVersionId});
            String sign = yozoUtils.generateSign(YozoParams.APP_ID, YozoParams.APP_KEY, parameter).getData();
            url = "http://eic.yozocloud.cn/api/view/file?fileVersionId=" + fileVersionId + "&appId=" + YozoParams.APP_ID + "&sign=" + sign;
        } else {
            if ("local".equals(configValueUtil.getFileType())) {
                url = YozoParams.DOMAINS + "/api/file/filedownload/" + type + "/" + secondFilePath + previewParams.getFileName();
            } else {
                url = minioUploadUtil.getFile(secondFilePath + fileName, type);
            }
            //encode编码
            String fileUrl = Base64.encodeBase64String(url.getBytes());
            url = configValueUtil.getKkFileUrl() + "onlinePreview?url=" + fileUrl;
        }
        return ActionResult.success(MsgCode.SU000.get(), url);
    }

    @NoDataSourceBind()
    @ApiOperation("kk本地文件预览")
    @GetMapping("/filedownload/{type}/{fileName}")
    public void filedownload(@PathVariable("type") String type, @PathVariable("fileName") String fileName,
                             HttpServletResponse response) {
        String filePath = FilePathUtil.getFilePath(type) + fileName;
        OutputStream os = null;
        if ("local".equals(configValueUtil.getFileType())) {
            //本地取对应文件
            File file = new File(filePath);
            try {
                os = response.getOutputStream();
                String contentType = Files.probeContentType(Paths.get(file.getAbsolutePath()));
                response.setHeader("Content-Type", contentType);
                response.setHeader("Content-Dispostion", "attachment;filename=" + new String(file.getName().getBytes(
                        "utf-8"), "ISO8859-1"));
                FileInputStream fileInputStream = new FileInputStream(file);

                WritableByteChannel writableByteChannel = Channels.newChannel(os);

                FileChannel channel = fileInputStream.getChannel();
                channel.transferTo(0, channel.size(), writableByteChannel);
                channel.close();
                os.flush();
                writableByteChannel.close();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (os != null) {
                        os.close();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @NoDataSourceBind()
    @ApiOperation("分片上传获取")
    @GetMapping("/chunk")
    public ActionResult checkChunk(Chunk chunk) {
        String type = chunk.getExtension();
        if (!OptimizeUtil.fileType(configValueUtil.getAllowUploadFileType(), type)) {
            return ActionResult.fail(MsgCode.FA017.get());
        }
        String identifier = chunk.getIdentifier();
        String path = FilePathUtil.getFilePath(FileTypeEnum.TEMPORARY);
        String filePath = XSSEscape.escapePath(path + identifier);
        List<File> chunkFiles = FileUtil.getFile(new File(filePath));
        List<Integer> existsChunk = chunkFiles.stream().filter(f -> {
            if (f.getName().endsWith(".tmp")) {
                FileUtils.deleteQuietly(f);
                return false;
            } else {
                return true;
            }
        }).map(f -> Integer.parseInt(f.getName().replace(chunk.getIdentifier().concat("-"), ""))).collect(Collectors.toList());
        ChunkRes chunkRes = ChunkRes.builder().merge(false).chunkNumbers(existsChunk).build();
        //
        return ActionResult.success(chunkRes);
    }


    @NoDataSourceBind()
    @ApiOperation("分片上传附件")
    @PostMapping("/chunk")
    public ActionResult upload(Chunk chunk, @RequestParam("file") MultipartFile file) {
        String type = chunk.getExtension();
        if (!OptimizeUtil.fileType(configValueUtil.getAllowUploadFileType(), type)) {
            return ActionResult.fail(MsgCode.FA017.get());
        }
        ChunkRes chunkRes = ChunkRes.builder().build();
        chunkRes.setMerge(false);
        File chunkFile = null;
        File chunkTmpFile = null;
        try {
            String filePath = FilePathUtil.getFilePath(FileTypeEnum.TEMPORARY);
            Integer chunkNumber = chunk.getChunkNumber();
            String identifier = chunk.getIdentifier();
            String chunkTempPath = filePath + identifier;
            File path = new File(chunkTempPath);
            if (!path.exists()) {
                path.mkdirs();
            }
            String chunkName = identifier.concat("-") + chunkNumber;
            String chunkTmpName = chunkName.concat(".tmp");
            chunkFile = new File(chunkTempPath, chunkName);
            chunkTmpFile = new File(chunkTempPath, chunkTmpName);
            if (chunkFile.exists() && chunkFile.length() == chunk.getCurrentChunkSize()) {
                System.out.println("该分块已经上传：" + chunkFile.getName());
            } else {
                @Cleanup InputStream inputStream = file.getInputStream();
                FileUtils.copyInputStreamToFile(inputStream, chunkTmpFile);
                chunkTmpFile.renameTo(chunkFile);
            }
            chunkRes.setMerge(chunk.getChunkNumber().equals(chunk.getTotalChunks()));
        } catch (Exception e) {
            try {
                FileUtils.deleteQuietly(chunkTmpFile);
                FileUtils.deleteQuietly(chunkFile);
            } catch (Exception ee) {
                e.printStackTrace();
            }
            return ActionResult.fail("上传异常");
        }
        return ActionResult.success(chunkRes);
    }

    @NoDataSourceBind()
    @ApiOperation("分片组装")
    @PostMapping("/merge")
    public ActionResult merge(MergeChunkDto mergeChunkDto) {
        String identifier = mergeChunkDto.getIdentifier();
        String path = FilePathUtil.getFilePath(FileTypeEnum.TEMPORARY);
        String filePath = XSSEscape.escapePath(path + identifier);
        String uuid = RandomUtil.uuId();
        String partFile = XSSEscape.escapePath(path + uuid + "." + mergeChunkDto.getExtension());
        UploaderVO vo = UploaderVO.builder().build();
        try {
            List<File> mergeFileList = FileUtil.getFile(new File(filePath));
            @Cleanup FileOutputStream destTempfos = new FileOutputStream(partFile, true);
            for (int i = 0; i < mergeFileList.size(); i++) {
                String chunkName = identifier.concat("-") + (i + 1);
                File files = new File(filePath, chunkName);
                if (files.exists()) {
                    FileUtils.copyFile(files, destTempfos);
                }
            }
            File partFiles = new File(partFile);
            if (partFiles.exists()) {
                MultipartFile multipartFile = FileUtil.createFileItem(partFiles);
                String type = mergeChunkDto.getType();
//                vo = uploaderVO(multipartFile, type);

                String modular = mergeChunkDto.getModular();
                if (StringUtils.isNotEmpty(modular)) {
                    vo = uploaderVO(multipartFile, type, modular);
                } else {
                    vo = uploaderVO(multipartFile, type);
                }
                FileUtil.deleteTmp(multipartFile);
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("合并分片失败:" + e);
        } finally {
            FileUtils.deleteQuietly(new File(filePath));
            FileUtils.deleteQuietly(new File(partFile));
        }
        vo.setFileSize(mergeChunkDto.getFileSize());
        return ActionResult.success(vo);
    }

    /**
     * 封装上传附件
     *
     * @param file
     * @param type
     * @return
     * @throws IOException
     */
    private UploaderVO uploaderVO(MultipartFile file, String type) throws IOException {
        String orgFileName = file.getOriginalFilename();
        String fileType = UpUtil.getFileType(file);
//        if (OptimizeUtil.fileSize(file.getSize(), 1024000)) {
//            return ActionResult.fail("上传失败，文件大小超过1M");
//        }
        String fileName = DateUtil.dateNow("yyyyMMdd") + "_" + RandomUtil.uuId() + "." + fileType;
        if (type.equals(FileTypeEnum.MAIL)) {
            type = FileTypeEnum.TEMPORARY;
        }
        String filePath = FilePathUtil.getFilePath(type.toLowerCase());
        UploaderVO vo = UploaderVO.builder().name(fileName).build();
        //上传文件
        UploadUtil.uploadFile(configValueUtil.getFileType(), type, fileName, file, filePath);
        if (type.equalsIgnoreCase(FileTypeEnum.USERAVATAR)) {
            vo.setUrl(UploaderUtil.uploaderImg(fileName));
        } else if (type.equalsIgnoreCase(FileTypeEnum.ANNEX)) {
//            UserInfo userInfo = userProvider.get();
//            vo.setUrl(UploaderUtil.uploaderFile(userInfo.getId() + "#" + fileName + "#" + type));
            vo.setUrl(UploaderUtil.uploaderImg("/api/file/Image/annex/", fileName));
        } else if (type.equalsIgnoreCase(FileTypeEnum.ANNEXPIC)) {
            vo.setUrl(UploaderUtil.uploaderImg("/api/file/Image/annex/", fileName));
        } else {
            vo.setUrl(UploaderUtil.uploaderImg("/api/file/Image/" + type.toLowerCase() + "/", fileName));
        }

        //上传到永中
        if ("yozo".equals(configValueUtil.getAllowPreviewFileType())) {
            try {
                @Cleanup InputStream inputStream = file.getInputStream();
                String s = yozoUtils.uploadFileInPreview(inputStream, orgFileName);
                Map<String, Object> map = JsonUtil.stringToMap(s);
                if ("操作成功".equals(map.get("message"))) {
                    Map<String, Object> dataMap = JsonUtil.stringToMap(String.valueOf(map.get("data")));
                    String verId = String.valueOf(dataMap.get("fileVersionId"));
                    vo.setFileVersionId(verId);
                }
            } catch (Exception e) {
                System.out.println("上传到永中失败");
                e.printStackTrace();
            }
        }
        return vo;
    }


    /**
     * 封装上传附件
     *
     * @param file
     * @param type    文件类型
     * @param modular 所属模块
     * @return
     * @throws IOException
     */
    private UploaderVO uploaderVO(MultipartFile file, String type, String modular) throws IOException {
        String orgFileName = file.getOriginalFilename();
        // 文件后缀名
        String fileType = UpUtil.getFileType(file);
//        if (OptimizeUtil.fileSize(file.getSize(), 1024000)) {
//            return ActionResult.fail("上传失败，文件大小超过1M");
//        }
        /**
         * 1 文件重命名
         */
        String fileName = DateUtil.dateNow("yyyyMMdd") + "_" + RandomUtil.uuId() + "." + fileType;
        /**
         *  2.1 通过fileType获取文件保存目录/minio的bucketName
         *  win或Linux本地存储路径
         */
        String bucketName = type.toLowerCase(); // 初始化 minio的bucketName
        String filePath = FilePathUtil.getFilePath(bucketName); // 获取win或Linux本地存储路径
        if (StringUtils.isNotEmpty(filePath)) {
            String[] arr = filePath.split("/|\\\\");
            if (arr.length > 0) {
                bucketName = arr[arr.length - 1];
            }
        }

        /**
         * 2.2 后半段目录 /年/月/日/模块/
         */
        String secondFilePath = DateUtil.dateNow("yyyy/MM/dd/") + modular + "/";
        UploaderVO vo = UploaderVO.builder().name(fileName).secondFilePath(secondFilePath).build();
        // 文件存储类型(local-本地存储，minio-网络存储)
        String fileType1 = configValueUtil.getFileType();
        //上传文件
        UploadUtil.uploadFile(fileType1, bucketName, fileName, file, filePath, secondFilePath);

        String apiUrl = "/api/file/Image/" + type + "/" + secondFilePath;
        vo.setUrl(UploaderUtil.uploaderImg(apiUrl, fileName));

        //上传到永中
        if ("yozo".equals(configValueUtil.getAllowPreviewFileType())) {
            try {
                @Cleanup InputStream inputStream = file.getInputStream();
                String s = yozoUtils.uploadFileInPreview(inputStream, orgFileName);
                Map<String, Object> map = JsonUtil.stringToMap(s);
                if ("操作成功".equals(map.get("message"))) {
                    Map<String, Object> dataMap = JsonUtil.stringToMap(String.valueOf(map.get("data")));
                    String verId = String.valueOf(dataMap.get("fileVersionId"));
                    vo.setFileVersionId(verId);
                }
            } catch (Exception e) {
                System.out.println("上传到永中失败");
                e.printStackTrace();
            }
        }
        return vo;
    }
}
